import 'dart:math';

import 'package:flutter/material.dart';
import 'bezier_util.dart';

class BasicBezierCurve extends StatelessWidget {
  const BasicBezierCurve({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: BasicBezierPainter(),
    );
  }
}

class BasicBezierPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
    var paint = Paint()..color = Color(0xFFE53020);
    paint.strokeWidth = 2.0;
    paint.style = PaintingStyle.stroke;

    // _drawHearWith2OrderBezier(canvas, paint, size);
    // _drawHeartWith3OrderBezier(canvas, paint, size);
    //_drawBezierShape(canvas, paint, size);
    // List<Color> colors = [
    //   Color(0xFFE05100),
    //   Color(0xFFF0A060),
    //   Color(0xFFE0E000),
    //   Color(0xFF10F020),
    //   Color(0xFF2080F5),
    //   Color(0xFF104FF0),
    //   Color(0xFFA040E5),
    //   Color(0xFFE05100),
    //   Color(0xFFF0A060),
    //   Color(0xFFE0E000),
    // ];
    // 更改点的位置可以实现很好看的动画效果
    // var p0 = Offset(0, size.height / 2);
    // var p1 = Offset(size.width / 4, size.height / 2 - 100);
    // var p2 = Offset(size.width * 3 / 4, size.height / 2 + 100);
    // var p3 = Offset(size.width, size.height / 2);
    // for (var i = 0; i < 20; ++i) {
    //   p1 = Offset(p1.dx, p1.dy + i);
    //   p2 = Offset(p2.dx, p2.dy + i);
    //   paint.color = colors[i % colors.length];
    //   paint.strokeWidth = 4;
    //   _drawBezierCurve(canvas, paint, [p0, p1, p2, p3], size);
    // }

    //_drawRandomCurves(canvas, paint, size);

    _drawFlames(canvas, paint, size);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }

  _drawFlames(Canvas canvas, Paint paint, Size size) {
    final colors = [
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080F5),
      Color(0xFF104FF0),
      Color(0xFFA040E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
    ];

    var startPoint = Offset(
      size.width / 2,
      size.height / 2,
    );
    var leftPoint = Offset(0, size.height / 4);

    for (var i = 0; i < 20; ++i) {
      var l01 = Offset(
        size.width / 2 - 8 * i,
        size.height / 4 - i * 5,
      );
      var l02 = Offset(
        size.width / 2 - 10 * i,
        5 * i.toDouble(),
      );

      paint.strokeWidth = 2.0;
      paint.color = colors[i % colors.length];
      _drawBezierCurve(canvas, paint, [startPoint, l01, l02, leftPoint], size);

      var rightPoint = Offset(
        size.width,
        size.height * 3 / 4,
      );

      var r01 = Offset(
        size.width / 2 + 8 * i,
        size.height * 3 / 4 + i * 5,
      );
      var r02 = Offset(
        size.width / 2 + 10 * i,
        size.height - 5 * i.toDouble(),
      );
      _drawBezierCurve(canvas, paint, [startPoint, r01, r02, rightPoint], size);
    }
  }

  _drawRandomCurves(Canvas canvas, Paint paint, Size size) {
    final colors = [
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080F5),
      Color(0xFF104FF0),
      Color(0xFFA040E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
    ];

    var p00 = Offset(
      0,
      0,
    );
    var p03 = Offset(
      size.width,
      size.height,
    );
    for (var i = 0; i < 100; ++i) {
      var p01 = Offset(
        Random().nextDouble() * size.width,
        -Random().nextDouble() * size.height * 2,
      );
      var p02 = Offset(
        -Random().nextDouble() * size.width * 2,
        -Random().nextDouble() * size.height,
      );

      paint.color = colors[i % colors.length];
      _drawBezierCurve(canvas, paint, [p00, p01, p02, p03], size);
    }
  }

  _drawHeartWith3OrderBezier(Canvas canvas, Paint paint, Size size) {
    final topWidth = 250.0;
    final bottomWidth = 248.0;
    final topSideY = 342.0;
    final bottomSideY = 660.0;
    var p40 = Offset(size.width / 2, 860);
    var p41 = Offset(size.width / 2 - bottomWidth, bottomSideY);
    var p42 = Offset(size.width / 2 - topWidth, topSideY);
    var p43 = Offset(size.width / 2, 580);
    var path5 = Path();
    path5.moveTo(p40.dx, p40.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p40, p41, p42, p43, t / 100.0);

      path5.lineTo(curvePoint.dx, curvePoint.dy);
    }
    paint.color = Colors.red[400]!;
    canvas.drawPath(path5, paint);

    var p45 = Offset(size.width / 2 + bottomWidth, bottomSideY);
    var p46 = Offset(size.width / 2 + topWidth, topSideY);
    var path6 = Path();
    path6.moveTo(p40.dx, p40.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p40, p45, p46, p43, t / 100.0);

      path6.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path6, paint);

    // canvas.drawCircle(p40, 2.0, pointPaint1);
    // canvas.drawCircle(p41, 2.0, pointPaint);
    // canvas.drawCircle(p42, 2.0, pointPaint1);
    // canvas.drawCircle(p43, 2.0, pointPaint);
    // canvas.drawCircle(p45, 2.0, pointPaint1);
    // canvas.drawCircle(p46, 2.0, pointPaint);
  }

  _drawBezierShape(Canvas canvas, Paint paint, Size size) {
    final height = 100.0;
    var p0 = Offset(0, size.height / 2 + height);
    var p1 = Offset(size.width / 4, size.height / 2 - height);
    var p2 = Offset(size.width * 3 / 4, size.height / 2 + height);
    var p3 = Offset(size.width, size.height / 2 - height);
    var path = Path();
    path.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);
    path.close();
    paint.style = PaintingStyle.fill;
    paint.color = Colors.blue[300]!;
    canvas.drawPath(path, paint);
  }

  _drawBezierCurve(Canvas canvas, Paint paint, List<Offset> points, Size size) {
    assert(points.length == 4);
    var path = Path();
    path.moveTo(points[0].dx, points[0].dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get3OrderBezierPoint(
          points[0], points[1], points[2], points[3], t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);
  }

  _drawHearWith2OrderBezier(Canvas canvas, Paint paint, Size size) {
    var pointPaint = Paint()..color = Color(0xFF2085E0);
    pointPaint.strokeWidth = 2.0;
    pointPaint.style = PaintingStyle.stroke;

    var pointPaint1 = Paint()..color = Color(0xFF20E040);
    pointPaint1.strokeWidth = 2.0;
    pointPaint1.style = PaintingStyle.stroke;

    final center1y = 220.0;
    final side1y = 75.0;
    final offset1x = 25.0;
    final offset2x = 2.0;
    final offset2y = 320.0;
    final center2y = 494.0;
    // 二阶贝塞尔曲线，0-1，取样间隔为0.01，共100个点
    var p0 = Offset(offset1x, center1y);
    var p1 = Offset(size.width / 4 - offset1x, side1y);
    var p2 = Offset(size.width / 2, center1y);
    var path1 = Path();
    path1.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get2OrderBezierPoint(p0, p1, p2, t / 100.0);

      path1.lineTo(curvePoint.dx, curvePoint.dy);
    }

    canvas.drawPath(path1, paint);

    var p3 = Offset(size.width * 3 / 4 + offset1x, side1y);
    var p4 = Offset(size.width - offset1x, center1y);
    var path2 = Path();
    path2.moveTo(p2.dx, p2.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get2OrderBezierPoint(p2, p3, p4, t / 100.0);

      path2.lineTo(curvePoint.dx, curvePoint.dy);
    }

    canvas.drawPath(path2, paint);

    var p5 = Offset(size.width - offset2x, offset2y);
    var p6 = Offset(size.width / 2, center2y);
    var path3 = Path();
    path3.moveTo(p4.dx, p4.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get2OrderBezierPoint(p4, p5, p6, t / 100.0);

      path3.lineTo(curvePoint.dx, curvePoint.dy);
    }

    canvas.drawPath(path3, paint);

    var p7 = Offset(offset2x, offset2y);
    var path4 = Path();
    path4.moveTo(p6.dx, p6.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get2OrderBezierPoint(p6, p7, p0, t / 100.0);

      path4.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path4, paint);

    canvas.drawCircle(p0, 2.0, pointPaint1);
    canvas.drawCircle(p1, 2.0, pointPaint);
    canvas.drawCircle(p2, 2.0, pointPaint);
    canvas.drawCircle(p3, 2.0, pointPaint);
    canvas.drawCircle(p4, 2.0, pointPaint1);
    canvas.drawCircle(p5, 2.0, pointPaint);
    canvas.drawCircle(p6, 2.0, pointPaint);
    canvas.drawCircle(p7, 2.0, pointPaint);
  }
}
